use common_base::{prelude::*, serde};
use common_exception::ErrorCode;

use crate::data::{
    dataset::{DatasetOwner, DatasetRef},
    DataObject, RowsetOwner,
};

// #[derive(Debug, serde::Serialize, serde::Deserialize)]
// #[serde(crate = "self::serde")]
// #[serde(rename_all = "camelCase")]
#[derive(Debug)]
pub struct FormDataModel {
    form_edit_status: FormEditStatus,
    self_rowset: RowsetOwner,
    bill_dataset_ref: DatasetRef, // here `Ref` point to self_rowset inner, must not point to other addr
}

// we must guarantee that: `bill_dataset_ref` and other NonNull field must NOT used between threads!!!
unsafe impl Send for FormDataModel {}

impl Into<DataObject> for FormDataModel {
    fn into(self) -> DataObject {
        DataObject::FormDataModel(shared_ref!(self))
    }
}

impl FormDataModel {
    pub fn deserizlize_from_json(mut form_data_model_json: serde_json::Value) -> Result<Self> {
        let form_edit_status = if let Some(form_edit_status) = form_data_model_json
            .get("formEditStatus")
            .and_then(|v| v.as_i64())
        {
            match form_edit_status {
                0 => FormEditStatus::View,
                1 => FormEditStatus::Create,
                2 => FormEditStatus::Change,
                4 => FormEditStatus::Lock,
                _ => {
                    return Err(ErrorCode::RequestInvalid(format!(
                        "invalid formEditStatus:{}",
                        form_edit_status
                    )))
                }
            }
        } else {
            return Err(ErrorCode::RequestInvalid(
                "can not deserizlize formEditStatus from FormDataModel",
            ));
        };

        let bill_dataset = if let Some(bill_dataset) = form_data_model_json.get_mut("billDataSet") {
            DatasetOwner::deserizlize_from_json(bill_dataset.take())?
        } else {
            return Err(ErrorCode::RequestInvalid(
                "can not deserizlize billDataSet from FormDataModel",
            ));
        };
        let bill_dataset_ref = (&bill_dataset).into();
        let mut self_rowset = RowsetOwner::default();
        self_rowset.insert_dataset(&bill_dataset.table_name.clone(), bill_dataset);

        Ok(Self {
            form_edit_status,
            self_rowset,
            bill_dataset_ref,
        })
    }
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(crate = "self::serde")]
#[serde(rename_all = "camelCase")]
pub enum FormEditStatus {
    View,
    Create,
    Change,
    Lock,
}
